package org.fastsyncer.manager.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.fastsyncer.common.constant.ConnectorConstant;
import org.fastsyncer.common.constant.MappingConstant;
import org.fastsyncer.common.entity.Mapping;
import org.fastsyncer.common.entity.DataSourceConfig;
import org.fastsyncer.common.entity.MappingTask;
import org.fastsyncer.connector.common.DatabaseConstant;
import org.fastsyncer.connector.database.DatabaseConnector;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ManagerUtil {

	private static Logger logger = LoggerFactory.getLogger(ManagerUtil.class);

	public static MappingTask parseMapping(String mapping) throws JSONException {
		MappingTask mappingTask = new MappingTask();

		// 1.解析连接器配置
		JSONObject rel = new JSONObject(mapping);
		
		// 2.获取mapping基本信息
		// 映射关系配置是否启用
		mappingTask.setEnable((boolean) rel.get("enable"));
		
		// 3.驱动模式
		String model = rel.getString("model");
		mappingTask.setModel(StringUtils.isNotBlank(model) ? model : mappingTask.getModel());
		// 映射关系配置名称
		mappingTask.setName(rel.getString("name"));

		// 4.解析过滤条件
		parseQuery(rel, mappingTask);

		// 5.获取驱动信息
		parseDriver(rel, mappingTask);

		// 6.获取配置策略
		parsePolicies(rel, mappingTask);
		return mappingTask;
	}

	public static void parseDriver(JSONObject rel, MappingTask mappingTask) throws JSONException {
		// 解析数据源
		JSONObject sourceMappingObj = rel.getJSONObject("sourceMapping");
		switch (sourceMappingObj.getString("connector")) {
		case ConnectorConstant.DB_CONNECTOR:
			// 1.获取同步数据源、目标源字段和数据源、目标源字段类型
			List<HashMap<String, Object>> sourceFileds = parseFields(sourceMappingObj.getJSONArray("fileds"));

			// 2.获取数据源配置
			DataSourceConfig sourceConfig = getDataSource(sourceMappingObj.getJSONObject("config"));

			// 3.获取数据量
			DatabaseConnector connector = DatabaseConnector.getInstance();
			String queryFilter = connector.getQuery(mappingTask.getQuery());
			Integer sourceRowCount = connector.getDataSourceConnector(sourceConfig, queryFilter).getRowCount();

			// 设置数据源配置、驱动类型、同步属性、数据量
			Mapping sourceMapping = new Mapping(sourceConfig, ConnectorConstant.DB_CONNECTOR, sourceFileds,
					sourceRowCount);

			// 4.拼接数据源执行命令
			if (sourceFileds != null && sourceFileds.size() > 0) {
				String sourceExcuteCommond = connector.getJdbcSQL(DatabaseConstant.OPERTION_SQL_QUERY, sourceConfig,
						sourceFileds, queryFilter);
				sourceMapping.getExcuteCommond().put(DatabaseConstant.OPERTION_SQL_QUERY, sourceExcuteCommond);
				logger.info("sourceExcuteQueryCommond:" + sourceExcuteCommond);
			}
			mappingTask.setSourceMapping(sourceMapping);
			break;
		default:
			break;
		}

		// 解析目标源
		JSONArray targetMappingsObj = rel.getJSONArray("mappings");
		int tlen = targetMappingsObj.length();
		List<Mapping> targetMappingList = new ArrayList<>();
		for (int i = 0; i < tlen; i++) {
			JSONObject targetMappingObj = targetMappingsObj.getJSONObject(i);
			switch (targetMappingObj.getString("connector")) {
			case ConnectorConstant.DB_CONNECTOR:
				// 1.获取同步数据源、目标源字段和数据源、目标源字段类型
				List<HashMap<String, Object>> targetFileds = parseFields(targetMappingObj.getJSONArray("fileds"));
				
				// 2.获取数据源配置
				DataSourceConfig targetConfig = getDataSource(targetMappingObj.getJSONObject("config"));

				// 3.获取数据量
				DatabaseConnector connector = DatabaseConnector.getInstance();
				Integer targetRowCount = connector.getDataSourceConnector(targetConfig).getRowCount();
				
				// 设置数据源配置、驱动类型、同步属性、数据量
				Mapping targetMapping = new Mapping(targetConfig, ConnectorConstant.DB_CONNECTOR, targetFileds,
						targetRowCount);
				
				// 4.拼接数据源执行命令
				String targetExcuteCommond = null;
				if (targetFileds != null && targetFileds.size() > 0) {
					// 4.1解析插入语句
					targetExcuteCommond = connector.getJdbcSQL(DatabaseConstant.OPERTION_SQL_INSERT, targetConfig,
							targetFileds, null);
					targetMapping.getExcuteCommond().put(DatabaseConstant.OPERTION_SQL_INSERT, targetExcuteCommond);
					logger.info("targetExcuteInsertCommond:" + targetExcuteCommond);

					// 4.2解析修改语句
					targetExcuteCommond = connector.getJdbcSQL(DatabaseConstant.OPERTION_SQL_UPDATE, targetConfig,
							targetFileds, null);
					targetMapping.getExcuteCommond().put(DatabaseConstant.OPERTION_SQL_UPDATE, targetExcuteCommond);
					logger.info("targetExcuteUpdateCommond:" + targetExcuteCommond);

					// 4.3解析删除语句
					targetExcuteCommond = connector.getJdbcSQL(DatabaseConstant.OPERTION_SQL_DELETE, targetConfig,
							targetFileds, null);
					targetMapping.getExcuteCommond().put(DatabaseConstant.OPERTION_SQL_DELETE, targetExcuteCommond);
					logger.info("targetExcuteDeleteCommond:" + targetExcuteCommond);
				}
				targetMappingList.add(targetMapping);
				break;
			default:
				break;
			}
		}
		mappingTask.setMappings(targetMappingList);
	}

	public static DataSourceConfig getDataSource(JSONObject datasource) throws JSONException {
		String driverClassName = (String) datasource.get("driverClassName");
		String url = (String) datasource.get("url");
		String username = (String) datasource.get("username");
		String password = (String) datasource.get("password");
		String table = (String) datasource.get("table");
		String primaryKey = (String) datasource.get("primaryKey");
		DataSourceConfig dataSourceConfig = new DataSourceConfig(driverClassName, url, table, primaryKey, username,
				password);

		// 解析表列名属性
		JSONArray column = datasource.getJSONArray("column");
		int colLen = column.length();
		if (column != null && colLen > 0) {
			List<HashMap<String, Object>> cols = new ArrayList<>();
			for (int i = 0; i < colLen; i++) {
				HashMap<String, Object> col = new HashMap<>();
				JSONObject c = (JSONObject) column.get(i);
				col.put("name", c.get("name"));
				col.put("typeName", c.get("typeName"));
				col.put("type", c.get("type"));
				cols.add(col);
			}
			dataSourceConfig.setColumn(cols);
		}
		return dataSourceConfig;
	}

	public static List<HashMap<String, Object>> parseFields(JSONArray filedsArray) throws JSONException {
		List<HashMap<String, Object>> sourceFileds = new ArrayList<HashMap<String, Object>>();
		int sLen = filedsArray.length();
		for (int i = 0; i < sLen; i++) {
			JSONObject object = filedsArray.getJSONObject(i);
			HashMap<String, Object> sfiled = new HashMap<String, Object>();
			sfiled.put("name", object.get("name"));
			sfiled.put("type", object.get("type"));
			sfiled.put("typeName", object.get("typeName"));
			sourceFileds.add(sfiled);
		}
		return sourceFileds;
	}

	public static void parseQuery(JSONObject rel, MappingTask mappingTask) throws JSONException {
		HashMap<String, List<HashMap<String, String>>> querys = new HashMap<String, List<HashMap<String, String>>>();
		JSONObject query = rel.getJSONObject("query");

		// 解析And过滤条件
		List<HashMap<String, String>> addList = parseQuery(query.getJSONArray(DatabaseConstant.OPERTION_SQL_QUERY_AND));
		querys.put(DatabaseConstant.OPERTION_SQL_QUERY_AND, addList);

		// 解析Or过滤条件
		List<HashMap<String, String>> orList = parseQuery(query.getJSONArray(DatabaseConstant.OPERTION_SQL_QUERY_OR));
		querys.put(DatabaseConstant.OPERTION_SQL_QUERY_OR, orList);

		// 保存解析条件
		mappingTask.setQuery(querys);
	}
	
	public static List<HashMap<String, String>> parseQuery(JSONArray querys) throws JSONException {
		// 解析过滤条件
		List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
		int qLen = querys.length();
		for (int i = 0; i < qLen; i++) {
			HashMap<String, String> q = new HashMap<String, String>();
			JSONObject f = (JSONObject) querys.get(i);
			q.put("name", f.getString("name"));
			q.put("operator", f.getString("operator"));
			q.put("value", f.getString("value"));
			list.add(q);
		}
		return list;
	}

	// 解析策略
	public static void parsePolicies(JSONObject rel, MappingTask mappingTask) throws JSONException {
		HashMap<String, HashMap<String, String>> policyMap = new HashMap<>();
		JSONObject policy = (JSONObject) rel.get("policy");

		// 解析增量同步，暂时针对canel实现
		if (!policy.isNull(MappingConstant.POLICY_INCREMENT)) {
			JSONObject policyInc = (JSONObject) policy.get(MappingConstant.POLICY_INCREMENT);
			HashMap<String, String> incMap = new HashMap<>();
			incMap.put("enable", policyInc.getString("enable"));

			// 增量类型
			String type = policyInc.getString("type");
			incMap.put("type", type);
			if (MappingConstant.POLICY_INCREMENT_MYSQL.equalsIgnoreCase(type)) {
				// 如果是mysql增量配置
				incMap.put("ip", policyInc.getString("ip"));
				incMap.put("port", String.valueOf(policyInc.getInt("port")));
				incMap.put("instance", policyInc.getString("instance"));
				incMap.put("database", policyInc.getString("database"));
				incMap.put("table", policyInc.getString("table"));
				policyMap.put(MappingConstant.POLICY_INCREMENT, incMap);

			} else if (MappingConstant.POLICY_INCREMENT_ORACLE.equalsIgnoreCase(type)) {
				// 如果是oracle增量配置
				incMap.put("scanAll", policyInc.getString("scanAll"));
				incMap.put("dictionary", String.valueOf(policyInc.getString("dictionary")));
				policyMap.put(MappingConstant.POLICY_INCREMENT, incMap);
			}
		}
		mappingTask.setPolicy(policyMap);
	}

}
